import {AdjustableRobot, PurchaseShopBehavior, Robot, SelectShopWhenServingBehavior, ServeCustomerBehavior} from "@/Game/Robot";
import {ShopClass} from "@/Game/Shop";
import {GetRandomInt, ShuffleArray, ShuffleArrayReturnNew} from "@/Game/CommonMethods";
import {CustomerClass} from "@/Game/Customer";
import {EventEffect} from "@/Game/Event";
import {AllDishListAsc} from "@/Game/Dish";
import {Game, GameStage} from "@/Game/Game";

export const defaultDishDrawPile = [0, 0, 0, 0, 0, 0, 1, 1];
export const defaultClearShopGroundPrice = [0, 2, 3, 4, 7, 8, 9, 10];

export class PlayerArea {
    game: Game;
    index: number;
    playByHuman: boolean;
    robot?: Robot;
    moneyOwned: number;
    dishDrawPile: number[];
    dishDiscardPile: number[];
    dishDiscardCount: number;
    trimDishEnabled: boolean;
    shopOwned: ShopClass[];

    selectingShop: boolean;

    constructor(game: Game, index: number, playByHuman: boolean) {
        this.game = game;
        this.index = index;
        this.playByHuman = playByHuman;
        if (!playByHuman) {
            this.robot = new AdjustableRobot(this, 2, 1, 0, 6, 1, 9, 15, true, PurchaseShopBehavior.Asc, ServeCustomerBehavior.HighestAllIncome, SelectShopWhenServingBehavior.First);
        }
        this.moneyOwned = index + 5;
        this.dishDrawPile = ShuffleArrayReturnNew(defaultDishDrawPile);
        this.dishDiscardCount = 0;
        this.dishDiscardPile = [0, 0, 0, 0];
        this.trimDishEnabled = false;
        this.shopOwned = [];
        this.selectingShop = false;
    }

    addDishToDiscardPile(dishClass: number) {
        this.dishDiscardPile[dishClass]++;
        this.dishDiscardCount++;
    }

    addShop(shop: ShopClass) {
        this.shopOwned.push(shop);
        for (let shop2 of this.shopOwned) {
            if (shop.LinkageBonus) {
                if (shop.LinkageBonusTypes?.includes(shop2.ShopType)) {
                    shop2.ExtraIncomeFromBonus += shop.LinkageBonus;
                }
            }
            if (shop2.LinkageBonus) {
                if (shop2.LinkageBonusTypes?.includes(shop.ShopType)) {
                    shop.ExtraIncomeFromBonus += shop2.LinkageBonus;
                }
            }
        }
    }

    playerTrim() {
        if (this.game.gameStage == GameStage.PlayerTrimDish) {
            if (this.dishDiscardCount <= 0 || this.moneyOwned < 3) {
                this.trimDishCompleted();
                return;
            }
            if (this.playByHuman) {
                this.trimDishEnabled = true;
                this.game.toast("请淘汰后厨菜品", -1);
            }
            else {
                this.trimDish(this.robot?.playerTrim(this.game) ?? -1);
            }
        }
    }

    trimDish(dishClass: number) {
        if (this.game.gameStage == GameStage.PlayerTrimDish) {
            if (dishClass < 0 || dishClass >= this.dishDiscardPile.length) {
                this.trimDishCompleted();
                return;
            }
            if (this.dishDiscardPile[dishClass] <= 0) {
                this.game.toast(`玩家 ${this.index} 没有此品级的菜品`);
                if (!this.playByHuman) {
                    this.trimDishCompleted();
                }
                return;
            }
            if (this.moneyOwned < 3) {
                this.game.toast(`玩家 ${this.index} 资金不足，移除菜品需要 3 两钱`);
                if (!this.playByHuman) {
                    this.trimDishCompleted();
                }
                return;
            }
            this.moneyOwned -= 3;
            this.dishDiscardPile[dishClass]--;
            this.dishDiscardCount--;
            this.game.commonArea.dishCount[dishClass]++;
            if (this.playByHuman) {
                this.trimDishCompleted();
            }
            else {
                setTimeout(() => {
                    this.trimDishCompleted();
                }, 500);
            }
        }
    }

    trimDishCompleted() {
        if (this.game.gameStage == GameStage.PlayerTrimDish) {
            this.game.showToast = false;
            this.trimDishEnabled = false;
            this.game.playerServe();
        }
    }

    shuffleDishes() {
        this.dishDiscardCount = 0;
        this.dishDiscardPile.forEach((count, dishClass) => {
            if (count > 0) {
                this.dishDrawPile.push(...new Array(count).fill(dishClass));
            }
        });
        this.dishDiscardPile = [0, 0, 0, 0];
        ShuffleArray(this.dishDrawPile);
    }

    getShouldConsume(customer: CustomerClass, shopSelected?: ShopClass): number {
        let result = customer.Consumption;
        let persistentEvent = this.game.commonArea.persistentEvent;
        if (persistentEvent) {
            switch (persistentEvent.EffectType) {
                case EventEffect.Consumption:
                    result += persistentEvent?.EffectStrength ?? 0;
                    for (let shop of this.shopOwned) {
                        if (shop.ConsumptionBonus && customer.Destinations.includes(shop.ShopType)) {
                            result += shop.ConsumptionBonus;
                        }
                    }
                    break;
                case EventEffect.ResolveOneShop:
                    if (shopSelected && customer.Destinations.includes(shopSelected.ShopType)) {
                        result += shopSelected.ConsumptionBonus ?? 0;
                    }
                    break;
            }
        }
        else {
            for (let shop of this.shopOwned) {
                if (shop.ConsumptionBonus && customer.Destinations.includes(shop.ShopType)) {
                    result += shop.ConsumptionBonus;
                }
            }
        }
        return result;
    }

    resolveDishes(customer: CustomerClass, shouldConsume: number, fixRandom: boolean = false): number {
        let earnedFromDish = 0;
        if (this.dishDrawPile.length + this.dishDiscardCount > 0) {
            let notConsumed = shouldConsume;
            while (notConsumed > 0) {
                let dishDrawPileLength = this.dishDrawPile.length;
                if (notConsumed >= dishDrawPileLength) {
                    notConsumed -= dishDrawPileLength;
                    for (let dishClass of this.dishDrawPile.splice(0)) {
                        this.addDishToDiscardPile(dishClass);
                        let dish = AllDishListAsc[dishClass];
                        earnedFromDish += dish.DirectIncome;
                        if (dish.RandomIncome) {
                            earnedFromDish += fixRandom ? 3.5 : GetRandomInt(1, 6);
                        }
                    }
                    this.shuffleDishes();
                }
                else {
                    for (let dishClass of this.dishDrawPile.splice(dishDrawPileLength - notConsumed)) {
                        this.addDishToDiscardPile(dishClass);
                        let dish = AllDishListAsc[dishClass];
                        earnedFromDish += dish.DirectIncome;
                        if (dish.RandomIncome) {
                            earnedFromDish += fixRandom ? 3.5 : GetRandomInt(1, 6);
                        }
                    }
                    notConsumed = 0;
                }
            }
        }
        return earnedFromDish;
    }

    resolveShop(shop: ShopClass, shouldConsume: number, fixRandom: boolean = false): number {
        let result = 0;
        if (shop.DirectIncome) {
            result += shop.DirectIncome;
        }
        if (shop.RandomIncome) {
            result += fixRandom ? 3.5 : GetRandomInt(1, 6);
        }
        if (shop.IncomeFromConsumption) {
            result += shouldConsume + shop.IncomeFromConsumption;
        }
        if (shop.IncomeFromShopCount) {
            result += this.shopOwned.length;
        }
        result += shop.ExtraIncomeFromBonus;
        let persistentEvent = this.game.commonArea.persistentEvent;
        if (persistentEvent && persistentEvent.EffectType == EventEffect.ShopIncome) {
            result += persistentEvent?.EffectStrength ?? 0;
        }
        return result;
    }

    serveCustomer(customer: CustomerClass): boolean {//返回结果用于表明是否需要选择商店
        if (this.game.gameStage == GameStage.PlayerServe) {
            this.game.showToast = false;
            let persistentEvent = this.game.commonArea.persistentEvent;
            if (persistentEvent && persistentEvent.EffectType == EventEffect.ResolveOneShop && this.shopOwned.length > 1 && this.playByHuman) {
                this.selectingShop = true;
                if (this.playByHuman) {
                    this.game.commonArea.humanSelectingCustomer = true;
                    this.game.toast("因为 门可罗雀 事件，请选择 1 个店铺进行结算", -1);
                }
                return true;
            }
            this.game.commonArea.customerQueue.splice(this.game.commonArea.selectedCustomerIndex, 1);
            this.game.commonArea.customerQueueEnabled = false;
            this.game.commonArea.customerAndEventDiscardPile.push(customer);
            let shouldConsume = this.getShouldConsume(customer);
            let earnedFromShop = 0;
            for (let shop of this.shopOwned) {
                if (customer.Destinations.includes(shop.ShopType)) {
                    earnedFromShop += this.resolveShop(shop, shouldConsume);
                }
            }
            this.moneyOwned += customer.Fund + earnedFromShop + this.resolveDishes(customer, shouldConsume);
            setTimeout(() => {
                if (this.game.checkWon && this.shopOwned.length >= 8 && this.moneyOwned >= 50) {
                    this.game.end();
                }
                else {
                    this.game.beforePlayerOperation();
                }
            }, 1000);
        }
        return false;
    }

    selectShop(index: number) {
        if (this.game.gameStage == GameStage.PlayerServe && this.selectingShop) {
            this.selectingShop = false;
            this.game.showToast = false;
            this.game.commonArea.humanSelectingCustomer = false;
            this.game.commonArea.customerQueueEnabled = false;
            let customer = this.game.commonArea.customerQueue.splice(this.game.commonArea.selectedCustomerIndex, 1)[0];
            this.game.commonArea.customerAndEventDiscardPile.push(customer);
            if (index >= this.shopOwned.length) {
                index = 0;
            }
            let shop = this.shopOwned[index];
            let shouldConsume = this.getShouldConsume(customer, shop);
            this.moneyOwned += customer.Fund + this.resolveShop(shop, shouldConsume) + this.resolveDishes(customer, shouldConsume);
            setTimeout(() => {
                if (this.game.checkWon && this.shopOwned.length >= 8 && this.moneyOwned >= 50) {
                    this.game.end();
                }
                else {
                    this.game.beforePlayerOperation();
                }
            }, 500);
        }
    }
}